-module(starling_drv_test).

-include_lib("eunit/include/eunit.hrl").
-define(NOTEST, false).

%% Depends on List being bound in scope.
-define(ks(X),
        element(2, element(2, lists:keysearch(X, 1, List)))).

starling_test_() ->
    {setup, local,
     fun setup/0,
     fun cleanup/1,
     fun({Pid, List}) ->
             [
              %% len tests
              ?_assert(len(Pid, ?ks(uuml)) == len(Pid, ?ks(uumlcomp))),
              ?_assert(len(Pid, ?ks('Uber')) == len(Pid, ?ks('Ubercomp'))),
              ?_assert(len(Pid, ?ks(uuml)) == 1),
              ?_assert(len(Pid, ?ks(u_uml)) == 2),
              ?_assert(len(Pid, ?ks('Uber')) == 4),

              %% equality tests
              ?_assert(eql(Pid, ?ks(uuml), ?ks(uumlcomp))),
              ?_assert(exact(Pid, ?ks(uuml), ?ks(uumlcomp))),
              ?_assert(eql(Pid, ?ks('Uber'), ?ks('Ubercomp'))),
              ?_assert(exact(Pid, ?ks('Uber'), ?ks('Ubercomp'))),
              ?_assert(not eql(Pid, ?ks(uuml), ?ks('Uber'))),
              ?_assert(eql(Pid, ?ks('Strasse'), ?ks(strasse_up))),

              %% upcase / downcase / capitalize tests
              ?_assert(upcase(Pid, ?ks(uuml)) == upcase(Pid, ?ks(uumlcomp))),
              ?_assert(upcase(Pid, ?ks('Uber')) == upcase(Pid, ?ks('Ubercomp'))),
              ?_assert(downcase(Pid, ?ks(uuml)) == downcase(Pid, ?ks(uumlcomp))),
              ?_assert(downcase(Pid, ?ks('Uber')) == downcase(Pid, ?ks('Ubercomp'))),
              ?_assert(upcase(Pid, ?ks('Strasse')) == upcase(Pid, ?ks(strasse_up))),

              ?_assert(upcase(Pid, downcase(Pid, ?ks('Uber'))) ==
                       upcase(Pid, downcase(Pid, ?ks('Uber')))),

              %% concat tests
              ?_assert(len(Pid, concat(Pid, ?ks(uuml), ?ks(uumlcomp))) ==
                       len(Pid, concat(Pid, ?ks(uumlcomp), ?ks(uuml)))),
              ?_assert(eql(Pid, concat(Pid, ?ks(uuml), ?ks(uumlcomp)),
                           concat(Pid, ?ks(uumlcomp), ?ks(uuml)))),
              ?_assert(len(Pid, concat(Pid, ?ks(uuml), ?ks(uumlcomp))) == 2),
              ?_assert(len(Pid, concat(Pid, ?ks('Uber'), ?ks('Ubercomp'))) == 8),

              %% substr tests
              ?_assert(eql(Pid, substr(Pid, ?ks('Uber'), 1),
                           substr(Pid, ?ks('Ubercomp'), 1))),
              ?_assert(len(Pid, substr(Pid, ?ks('Uber'), 2, 3)) ==
                       len(Pid, substr(Pid, ?ks('Ubercomp'), 2, 3))),
              ?_assert(len(Pid, substr(Pid, ?ks('Ubercomp'), 2, 3)) == 3)
             ]
     end
    }.

new(Pid, List) when is_list(List) ->
    Uc = xmerl_ucs:from_utf8(List),
    Utf16Be = list_to_binary(lists:reverse([0,0|lists:reverse(xmerl_ucs:to_utf16be(Uc))])),
    {ok, Norm} = starling_drv:normalize(Pid, infinity, Utf16Be),
    Norm.

setup() ->
    {ok, Pid} = gen_server:start(starling_drv_gen_server, [?STARLING_DRIVER_DIR, "starling_drv", []], []),
    {Pid, [
           %% U+00FC -- ü
           { uuml,       new(Pid, [16#C3, 16#BC]) },
           %% U+0075 U+0308 -- u followed by combining umlaut
           { uumlcomp,   new(Pid, [16#75, 16#CC, 16#88]) },
           %% U+0075 U+00A8 -- u followed by non-combining umlaut.
           { u_uml,      new(Pid, [16#75, 16#C2, 16#A8]) },
           %% Über
           { 'Uber',     new(Pid, [16#C3, 16#9C, 16#62, 16#65, 16#72]) },
           %% Über, but with combined Ü.
           { 'Ubercomp', new(Pid, [16#55, 16#CC, 16#88, 16#62, 16#65, 16#72]) },
           %%  Straße: U+0053, U+0074, U+0072, U+0061, U+00DF, U+0065
           { 'Strasse',  new(Pid, [83, 116, 114, 97, 195, 159, 101]) },
           %% STRASSE
           { strasse_up, new(Pid, [83, 84, 82, 65, 83, 83, 69]) },

           { duff, <<>> }]}.

len(Pid, UString) ->
    {ok, Len} = starling_drv:lengthg(Pid, infinity, UString),
    Len.

eql(Pid, UStringL, UStringR) ->
    starling_drv:equal(Pid, infinity, UStringL, UStringR).

exact(Pid, UStringL, UStringR) ->
    starling_drv:exact(Pid, infinity, UStringL, UStringR).

upcase(Pid, UString) ->
    {ok, UString2} = starling_drv:upcase(Pid, infinity, UString),
    UString2.

downcase(Pid, UString) ->
    {ok, UString2} = starling_drv:downcase(Pid, infinity, UString),
    UString2.

concat(Pid, UString1, UString2) ->
    starling_drv:concat(Pid, infinity, UString1, UString2).

substr(Pid, UString, Len) ->
    substr(Pid, UString, 1, Len).

substr(Pid, UString, Start, Len) ->
    {ok, Res} = starling_drv:substr(Pid, infinity, UString, Start, Len),
    Res.

%% Unload driver?
cleanup(_) ->
    ok.

